#include "http-request.h"

#include <sstream>

#include "util/logger/logger.h"
#include "util/strutil.h"
#include "util/fs.h"


HttpRequest::Method HttpRequest::method() const {
    const beast::http::verb method = request_.method();
    switch (method) {
    case beast::http::verb::get:
        return Method::Get;
    case beast::http::verb::post:
        return Method::Post;
    default:
        LOGE << "unknown request method: " << int(method);
        return Method::Unknown;
    }
}

std::string HttpRequest::relative(const std::string_view &base) const {
    const std::string target(request_.target());
    const std::string s(fs::path(target).lexically_relative(std::string(base)).generic_string());
    if (s != ".") {
        return s;
    } else {
        return std::string();
    }
}

bool HttpRequest::under(const std::string_view &base) const {
    if (base.empty()) {
        return true;
    }
    const std::string_view target = request_.target();
    if (strutil::startWith(target, base)) {
        if (base.back() == '/') {
            return true;
        } else if (target.size() == base.size()) {
            return true;
        } else {
            return target.size() > base.size() && target[base.size()] == '/';
        }
    } else {
        return false;
    }
}

std::string_view HttpRequest::ifNonMatch() const {
    auto it = request_.find(beast::http::field::if_none_match);
    if (it != request_.end()) {
        return it->value();
    } else {
        return std::string_view();
    }
}

bool HttpRequest::acceptGzip() const {
    namespace s = strutil;
    auto it = request_.find(beast::http::field::accept_encoding);
    if (it != request_.end()) {
        s::strviews parts = s::split(it->value(), ',');
        for (const std::string_view &part : parts) {
            if (s::equalIgnoreCase(s::trim(part), "gzip")) {
                return true;
            }
        }
    }
    return false;
}

static const std::string_view kEmptyStringView{""};

std::string_view HttpRequest::paramValueOf(const std::string_view &name) const
{
    auto it = request_.base().find(name);
    if (it != request_.base().end()) {
        return it->value();
    }
    return kEmptyStringView;
}

std::string HttpRequest::makeLogInfo(const Impl &request) {
    std::ostringstream ss;
    ss << "(" << request.method_string();
    ss << "," << request.target();
    ss << "," << request.version();
    if (request.payload_size().has_value()) {
        ss << "," << request.payload_size().value();
    }
    ss << ")";
    return ss.str();
}

